#include "LevelManager.h"

#include <SFML/Graphics.hpp>

#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <iterator>
#include <sstream>

#include "GameService.h"
#include "WindowManager.h"
#include "EntityManager.h"

#include "../Data/Node.h"

using namespace std;

//-------------------------------------------------------------------------------------------
LevelManager::LevelManager()
{
	m_pRootNode = 0;
}

//-------------------------------------------------------------------------------------------
LevelManager::~LevelManager()
{
}

//-------------------------------------------------------------------------------------------
void LevelManager::Setup()
{
	m_pWindowManager = GameService::GetInstance()->GetWindowManager();
	m_pEntityManager = GameService::GetInstance()->GetEntityManager();
}

//-------------------------------------------------------------------------------------------
void LevelManager::Tick(float DeltaTime)
{
	//Draw nodes - debug
	m_processedNodes.clear();
	DrawNode(0);
}

//-------------------------------------------------------------------------------------------
void LevelManager::DrawNode(int nodeID)
{
	Node* pNode = GetNode(nodeID);

	if (!pNode)
		return;

	// If this node has already been drawn, skip it.
	if (m_processedNodes.find(pNode) != m_processedNodes.end())
		return;

	m_processedNodes.insert(pNode);

	sf::RenderWindow* pWindow = m_pWindowManager->GetWindow();

	sf::CircleShape nodeG = sf::CircleShape(7);
	
	nodeG.setPosition(
		GetPlayAreaX(pNode->GetX()),  
		GetPlayAreaY(pNode->GetY()));
	nodeG.setOrigin(7, 7);
	pWindow->draw(nodeG);


	//Process this nodes connections
	DrawNode(pNode->GetConnection(Node::UP));
	DrawConnection(nodeID, pNode->GetConnection(Node::UP));
	DrawNode(pNode->GetConnection(Node::DOWN));
	DrawConnection(nodeID, pNode->GetConnection(Node::DOWN));
	DrawNode(pNode->GetConnection(Node::LEFT));
	DrawConnection(nodeID, pNode->GetConnection(Node::LEFT));
	DrawNode(pNode->GetConnection(Node::RIGHT));
	DrawConnection(nodeID, pNode->GetConnection(Node::RIGHT));
}

//-------------------------------------------------------------------------------------------
void LevelManager::DrawConnection(int node1, int node2)
{
	Node* pNode1 = GetNode(node1);
	Node* pNode2 = GetNode(node2);

	if (!pNode1 || !pNode2)
		return;

	sf::RenderWindow* pWindow = m_pWindowManager->GetWindow();

	//Draw connections to this node.
	sf::Vector2f origin;
	origin.x = GetPlayAreaX(pNode1->GetX()) + 4;
	origin.y = GetPlayAreaY(pNode1->GetY()) + 4;

	sf::Vector2f target;
	target.x = GetPlayAreaX(pNode2->GetX());
	target.y = GetPlayAreaY(pNode2->GetY());

	sf::Vertex line[2] = {origin, target};
	pWindow->draw(line, 2, sf::Lines);
}

//-------------------------------------------------------------------------------------------
float LevelManager::GetPlayAreaX(float X)
{
	return 100 + ( X * (m_pWindowManager->GetWidth() - 200));
}

//-------------------------------------------------------------------------------------------
float LevelManager::GetPlayAreaY(float Y)
{
	return 100 + ( Y * (m_pWindowManager->GetHeight() - 200));
}

//-------------------------------------------------------------------------------------------
void LevelManager::BeginGame()
{
	LoadLevel("");
}

//-------------------------------------------------------------------------------------------
void LevelManager::LoadLevel(sf::String levelName)
{
	if (m_pRootNode)
		return;

	ifstream file;
	string fileName = "./Levels/Level.txt";
	file.open(fileName.c_str());

	if (!file)
		return;

	string lineIn;
	while(std::getline(file, lineIn)) // Read line by line
	{
		if (lineIn.size() == 0)
			continue;

		if (lineIn.at(0) == '#')
			continue;

		std::vector<std::string> values;
		split(lineIn, values);

		if (values.size() != 6)
			continue;

		float X = ::atof(values[0].c_str());
		float Y = ::atof(values[1].c_str());

		int U = ::atof(values[2].c_str()) - 1;
		int D = ::atof(values[3].c_str()) - 1;
		int L = ::atof(values[4].c_str()) - 1;
		int R = ::atof(values[5].c_str()) - 1;

		int ID = AddNode(X, Y);

		AddConnection(ID, U, Node::UP);
		AddConnection(ID, D, Node::DOWN);
		AddConnection(ID, L, Node::LEFT);
		AddConnection(ID, R, Node::RIGHT);
	}

	m_pRootNode = GetNode(0);

	if (!m_pRootNode)
		return;

	m_pEntityManager->AddPlayer(0);
	m_pEntityManager->AddEntity(0);
	m_pEntityManager->AddEntity(0);
	m_pEntityManager->AddEntity(0);
	m_pEntityManager->AddEntity(0);
}

//-------------------------------------------------------------------------------------------
void LevelManager::split(const std::string& str, std::vector<std::string>& v) {
  std::stringstream ss(str);
  ss >> std::noskipws;
  std::string field;
  char ws_delim;
  while(1) {
    if( ss >> field)
      v.push_back(field);
    else if (ss.eof())
      break;
    else
      //v.push_back(std::string());
    ss.clear();
    ss >> ws_delim;
  }
}

//-------------------------------------------------------------------------------------------
int LevelManager::AddNode(float x, float y)
{
	int NodeID = m_nodeLookup.size();
	m_nodeLookup[NodeID] = new Node(x, y);
	m_nodeLookup[NodeID]->SetID(NodeID);
	return NodeID;
}

//-------------------------------------------------------------------------------------------
void LevelManager::AddConnection(int from, int to, Node::Direction dir)
{
	Node* pFrom = GetNode(from);

	pFrom->AddConnection(to, dir);
}

//-------------------------------------------------------------------------------------------
Node* LevelManager::GetNode(int NodeID)
{
	if (m_nodeLookup.find(NodeID) == m_nodeLookup.end())
		return 0;

	return m_nodeLookup[NodeID];
}

//-------------------------------------------------------------------------------------------